
var VSHADER_SOURCE =
    'attribute vec3 a_Position;\n' +
    'attribute vec3 a_TexCoord;\n' +
    'uniform mat4 u_MvpMatrix;\n' +
    'uniform mat4 u_ViewMatrix;\n' +
    'varying vec3 v_TexCoord;\n' +
    'void main() {\n' +
    '  gl_Position = u_MvpMatrix * vec4(a_Position,1.0);\n' +
    '  v_TexCoord = a_Position;\n' +
    '}\n';

// Fragment shader program
var FSHADER_SOURCE =
    '#ifdef GL_ES\n' +
    'precision highp float;\n' +
    '#endif\n' +
    'uniform samplerCube u_SamplerCube;\n' +
    'varying vec3 v_TexCoord;\n' +
    'void main() {\n' +
    '  gl_FragColor = textureCube(u_SamplerCube, v_TexCoord);\n' +
    '}\n';
// Retrieve <canvas> element

var HWebgl=function () {
    //this.canvasId=canvasId
    var CreatePano=function (canvasId,f_image,b_image,l_image,r_image,u_image,d_image,angle){
        var canvas = document.getElementById(canvasId);
        // Get the rendering context for WebGL
        var gl = getWebGLContext(canvas);
        if (!gl) {
            console.log('Failed to get the rendering context for WebGL');
            return;
        }

        // Initialize shaders
        if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
            console.log('Failed to intialize shaders.');
            return;
        }

        // Set the vertex information
        var n = initVertexBuffers(gl);
        if (n < 0) {
            console.log('Failed to set the vertex information');
            return;
        }

        // Set the clear color and enable the depth test
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clearDepth(1.0);
        gl.clear(webgl.COLOR_BUFFER_BIT|webgl.DEPTH_BUFFER_BIT);
        gl.enable(gl.DEPTH_TEST);

        // Get the storage locations of uniform variables
        var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
        if (!u_MvpMatrix) {
            console.log('Failed to get the storage location of uniform variable');
            return;
        }

        // Calculate the view projection matrix
        var viewProjMatrix = new Matrix4();
        viewProjMatrix.setPerspective(angle, canvas.width / canvas.height, 0.5, 50.0);
        viewProjMatrix.lookAt(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0);

        // Register the event handler
        var currentAngle = [0.0, 0.0]; // Current rotation angle ([x-axis, y-axis] degrees)
        initEventHandlers(canvas, currentAngle);

        // Set texture
        if (!initTextures(gl,f_image,b_image,l_image,r_image,u_image,d_image)) {
            console.log('Failed to intialize the texture.');
            return;
        }
        var tick = function() {   // Start drawing
            draw(gl, n, viewProjMatrix, u_MvpMatrix, currentAngle);
            requestAnimationFrame(tick, canvas);
        };
        tick();
    }

     return {
         CreatePano:CreatePano
     }

}

function initVertexBuffers(gl) {
    // Create a cube
    //    v6----- v5
    //   /|      /|
    //  v1------v0|
    //  | |     | |
    //  | |v7---|-|v4
    //  |/      |/
    //  v2------v3
    var vertices = new Float32Array([   // Vertex coordinates
        1.0,1.0, 1.0,
        1.0, -1.0, 1.0,
        -1.0, -1.0, 1.0,
        -1.0, 1.0, 1.0,
        1.0, 1.0, -1.0,
        1.0, -1.0, -1.0,
        -1.0, -1.0, -1.0,
        -1.0, 1.0, -1.0
    ]);

    var texCoords = new Float32Array([   // Texture coordinates
        1.0, 1.0,   0.0, 1.0,   0.0, 0.0,   1.0, 0.0,    // v0-v1-v2-v3 front
        0.0, 1.0,   0.0, 0.0,   1.0, 0.0,   1.0, 1.0,    // v0-v3-v4-v5 right
        1.0, 0.0,   1.0, 1.0,   0.0, 1.0,   0.0, 0.0,    // v0-v5-v6-v1 up
        1.0, 1.0,   0.0, 1.0,   0.0, 0.0,   1.0, 0.0,    // v1-v6-v7-v2 left
        0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   0.0, 1.0,    // v7-v4-v3-v2 down
        0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   0.0, 1.0     // v4-v7-v6-v5 back
    ]);
    // Indices of the vertices
    var indices = new Uint8Array([
        //front
        0,1,2,
        2,3,0,
        //back
        4,7,6,
        6,5,4,
        //left
        3,2,6,
        6,7,3,
        //right
        4,5,1,
        1,0,4,
        //up
        4,0,3,
        3,7,4,
        //down
        1,5,6,
        6,2,1
    ]);

    // Create a buffer object
    var indexBuffer = gl.createBuffer();
    if (!indexBuffer) {
        return -1;
    }

    // Write vertex information to buffer object
    if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) return -1; // Vertex coordinates
   // if (!initArrayBuffer(gl, texCoords, 2, gl.FLOAT, 'a_TexCoord')) return -1;// Texture coordinates

    // Unbind the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, null);

    // Write the indices to the buffer object
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

    return indices.length;
}

function initEventHandlers(canvas, currentAngle) {
    var dragging = false;         // Dragging or not
    var lastX = -1, lastY = -1;   // Last position of the mouse
    if(!IsPC()) {

        canvas.addEventListener('touchstart', function (ev) {

            var x = ev.targetTouches[0].screenX, y = ev.targetTouches[0].screenY;

            // Start dragging if a moue is in <canvas>
            var rect = ev.target.getBoundingClientRect();
            if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
                lastX = x;
                lastY = y;
                dragging = true;
            }
        });
        canvas.addEventListener('touchmove', function (ev) {
            var x = ev.targetTouches[0].screenX, y = ev.targetTouches[0].screenY;
            // var x = ev.clientX, y = ev.clientY;
            if (dragging) {
                var factor = 100 / canvas.height; // The rotation ratio
                var dx = factor * (x - lastX);
                var dy = factor * (y - lastY);
                // Limit x-axis rotation angle to -90 to 90 degrees
                currentAngle[0] = Math.max(Math.min(currentAngle[0] + dy, 90.0), -90.0);
                currentAngle[1] = currentAngle[1] - dx;
            }
            lastX = x, lastY = y;
        });
        canvas.addEventListener('touchend', function (ev) {
            dragging = false;
        })
    }else {

        canvas.addEventListener('mousedown', function (ev) {

            var x = ev.clientX, y = ev.clientY;

            // Start dragging if a moue is in <canvas>
            var rect = ev.target.getBoundingClientRect();
            if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
                lastX = x;
                lastY = y;
                dragging = true;
            }
        });
        canvas.addEventListener('mousemove', function (ev) {
            var x = ev.clientX, y = ev.clientY;
            // var x = ev.clientX, y = ev.clientY;
            if (dragging) {
                var factor = 100 / canvas.height; // The rotation ratio
                var dx = factor * (x - lastX);
                var dy = factor * (y - lastY);
                // Limit x-axis rotation angle to -90 to 90 degrees
                currentAngle[0] = Math.max(Math.min(currentAngle[0] + dy, 90.0), -90.0);
                currentAngle[1] = currentAngle[1] - dx;
            }
            lastX = x, lastY = y;
        });
        canvas.addEventListener('mouseup', function (ev) {
            dragging = false;
        })
    }
    //canvas.onmousedown = function(ev) {   // Mouse is pressed
    //    var x = ev.clientX, y = ev.clientY;
    //    // Start dragging if a moue is in <canvas>
    //    var rect = ev.target.getBoundingClientRect();
    //    console.log(rect)
    //    if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
    //        lastX = x; lastY = y;
    //        dragging = true;
    //    }
    //};
    //
    //canvas.onmouseup = function(ev) { dragging = false;  }; // Mouse is released
    //
    //canvas.onmousemove = function(ev) { // Mouse is moved
    //    var x = ev.clientX, y = ev.clientY;
    //    if (dragging) {
    //        var factor = 100/canvas.height; // The rotation ratio
    //        var dx = factor * (x - lastX);
    //        var dy = factor * (y - lastY);
    //        // Limit x-axis rotation angle to -90 to 90 degrees
    //        currentAngle[0] = Math.max(Math.min(currentAngle[0] + dy, 90.0), -90.0);
    //        currentAngle[1] = currentAngle[1] - dx;
    //    }
    //    lastX = x, lastY = y;
    //};
}


function draw(gl, n, viewProjMatrix, u_MvpMatrix, currentAngle) {
    // Caliculate The model view projection matrix and pass it to u_MvpMatrix
    var g_MvpMatrix = new Matrix4(); // Model view projection matrix
    g_MvpMatrix.set(viewProjMatrix);
    g_MvpMatrix.rotate(currentAngle[0], 1.0, 0.0, 0.0); // Rotation around x-axis
    g_MvpMatrix.rotate(currentAngle[1], 0.0, 1.0, 0.0); // Rotation around y-axis
    gl.uniformMatrix4fv(u_MvpMatrix, false, g_MvpMatrix.elements);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);     // Clear buffers
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);   // Draw the cube
}

function initArrayBuffer(gl, data, num, type, attribute) {
    // Create a buffer object
    var buffer = gl.createBuffer();
    if (!buffer) {
        console.log('Failed to create the buffer object');
        return false;
    }
    // Write date into the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
    // Assign the buffer object to the attribute variable
    var a_attribute = gl.getAttribLocation(gl.program, attribute);
    if (a_attribute < 0) {
        console.log('Failed to get the storage location of ' + attribute);
        return false;
    }
    gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
    // Enable the assignment to a_attribute variable
    gl.enableVertexAttribArray(a_attribute);

    return true;
}
function initTextures(gl,f_image,b_image,l_image,r_image,u_image,d_image) {
    var textureObject = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, textureObject);
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, document.getElementById(u_image));
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, document.getElementById(d_image));
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, document.getElementById(l_image));
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, document.getElementById(r_image));
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, document.getElementById(f_image));
    gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, document.getElementById(b_image));
    // Create a texture object
    //var texture = gl.createTexture();
    //if (!texture) {
    //    console.log('Failed to create the texture object');
    //    return false;
    //}
    // Get the storage location of u_Sampler
    var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
    //if (!u_Sampler0) {
    //    console.log('Failed to get the storage location of u_Sampler');
    //    return false;
    //}

    // Create the image object
    var image = new Image();
    if (!image) {
        console.log('Failed to create the image object');
        return false;
    }
    // Register the event handler to be called when image loading is completed
    image.onload = function(){ loadTexture(gl, textureObject, u_Sampler, image,0); };
    // Tell the browser to load an Image
    // Tell the browser to load an Image
    image.src = document.getElementById(b_image).src;
    return true;
}
function loadTexture(gl, texture, u_Sampler, image,texUnit) {
    //gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);  // Flip the image Y coordinate
    // Activate texture unit0
    //gl.activeTexture(gl.TEXTURE0);
    gl.activeTexture(gl.TEXTURE0);
    // Bind the texture object to the target

    //gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
    //gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    // Set texture parameters
    // Set the image to texture
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
    gl.uniform1i(u_Sampler, 0);
    // Pass the texure unit 0 to u_Sampler
}
function IsPC() {
    var userAgentInfo = navigator.userAgent;
    var Agents = ["Android", "iPhone",
        "SymbianOS", "Windows Phone",
        "iPad", "iPod"];
    var flag = true;
    for (var v = 0; v < Agents.length; v++) {
        if (userAgentInfo.indexOf(Agents[v]) > 0) {
            flag = false;
            break;
        }
    }
    return flag;
}

